package com.own.business.log.operation.persistence.business.config;

import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.query_dsl.MatchQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.RangeQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.TermQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.TermsQuery;
import co.elastic.clients.json.JsonData;
import com.own.business.log.operation.persistence.entity.po.LogOperation;
import com.own.business.log.operation.persistence.entity.po.LogOperationElasticPo;
import com.own.business.log.operation.persistence.entity.query.LogOperationQuery;
import com.own.business.log.operation.persistence.entity.vo.LogOperationElasticVo;
import com.own.component.elastic.constant.E;
import com.own.component.elastic.service.config.ElasticSearchConfig;
import com.own.component.util.time.LocalDateTimeUtil;
import com.own.constant.ConstantDateFormatPattern;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.stream.Collectors;

/**
 * LogOperationElasticServiceImpl
 *
 * @author chenxueli
 * @date 2023-12-15 11:42:00
 */
@Slf4j
@Service
public class LogOperationElasticConfig {

    public static final String INDEX_NAME = "log-operation";

    private static final ZoneId DEFAULT_ZONE_ID = ZoneId.systemDefault();

    /**
     * 默认的查询配置
     */
    public static final ElasticSearchConfig<LogOperation, LogOperationElasticPo, LogOperationElasticVo, LogOperationQuery> DEFAULT_CONFIG =
            ElasticSearchConfig.<
                            LogOperation,
                            LogOperationElasticPo,
                            LogOperationElasticVo,
                            LogOperationQuery
                            >builder()
                    .boolQueryBuilder((query, builder) -> {
                        if (query.getLevel() != null) {
                            builder.must(TermQuery.of(m -> m.field(LogOperationElasticPo.Fields.level).value(query.getLevel()))._toQuery());
                        }
                        if (query.getUserId() != null) {
                            builder.must(TermQuery.of(m -> m.field(LogOperationElasticPo.Fields.fkUserId).value(query.getUserId()))._toQuery());
                        }
                        if (StringUtils.isNotBlank(query.getToken())) {
                            builder.must(TermQuery.of(m -> m.field(E.buildKeyword(LogOperationElasticPo.Fields.token)).value(query.getToken()))._toQuery());
                        }
                        if (StringUtils.isNotBlank(query.getMethodName())) {
                            builder.must(TermQuery.of(m -> m.field(E.buildKeyword(LogOperationElasticPo.Fields.methodName)).value(query.getMethodName()))._toQuery());
                        }
                        if (query.getStatus() != null) {
                            builder.must(TermQuery.of(m -> m.field(LogOperationElasticPo.Fields.status).value(query.getStatus()))._toQuery());
                        }
                        if (StringUtils.isNotBlank(query.getUserName())) {
                            builder.must(MatchQuery.of(m -> m.field(LogOperationElasticPo.Fields.userName).query(query.getUserName()))._toQuery());
                        }
                        if (StringUtils.isNotBlank(query.getClient())) {
                            builder.must(TermQuery.of(m -> m.field(E.buildKeyword(LogOperationElasticPo.Fields.client)).value(query.getClient()))._toQuery());
                        }
                        if (StringUtils.isNotBlank(query.getIp())) {
                            builder.must(MatchQuery.of(m -> m.field(E.buildKeyword(LogOperationElasticPo.Fields.ip)).query(query.getIp()))._toQuery());
                        }
                        if (StringUtils.isNotBlank(query.getModuleName())) {
                            builder.must(MatchQuery.of(m -> m.field(LogOperationElasticPo.Fields.moduleName).query(query.getModuleName()))._toQuery());
                        }
                        if (StringUtils.isNotBlank(query.getOperationName())) {
                            builder.must(MatchQuery.of(m -> m.field(LogOperationElasticPo.Fields.operationName).query(query.getOperationName()))._toQuery());
                        }
                        if (query.getRequestTimeStartObject() != null) {
                            builder.filter(RangeQuery.of(r -> r.field(LogOperationElasticPo.Fields.requestTime).gte(JsonData.of(ZonedDateTime.of(query.getRequestTimeStartObject(), DEFAULT_ZONE_ID))))._toQuery());
                        } else {
                            if (StringUtils.isNotBlank(query.getRequestTimeStart())) {
                                var requestTimeStart = LocalDateTimeUtil.parse(query.getRequestTimeStart(),
                                        ConstantDateFormatPattern.Pattern.DATETIME,
                                        ConstantDateFormatPattern.Pattern.DATETIME_MM,
                                        ConstantDateFormatPattern.Pattern.DATE
                                );
                                builder.filter(RangeQuery.of(r -> r.field(LogOperationElasticPo.Fields.requestTime).gte(JsonData.of(ZonedDateTime.of(requestTimeStart, DEFAULT_ZONE_ID))))._toQuery());
                            }
                        }
                        if (query.getRequestTimeEndObject() != null) {
                            builder.filter(RangeQuery.of(r -> r.field(LogOperationElasticPo.Fields.requestTime).lte(JsonData.of(ZonedDateTime.of(query.getRequestTimeEndObject(), DEFAULT_ZONE_ID))))._toQuery());
                        } else {
                            if (StringUtils.isNotBlank(query.getRequestTimeEnd())) {
                                var requestTimeEnd = LocalDateTimeUtil.parse(query.getRequestTimeEnd(),
                                        ConstantDateFormatPattern.Pattern.DATETIME,
                                        ConstantDateFormatPattern.Pattern.DATETIME_MM,
                                        ConstantDateFormatPattern.Pattern.DATE
                                );
                                builder.filter(RangeQuery.of(r -> r.field(LogOperationElasticPo.Fields.requestTime).lte(JsonData.of(ZonedDateTime.of(requestTimeEnd, DEFAULT_ZONE_ID))))._toQuery());
                            }
                        }
                        if (StringUtils.isNotBlank(query.getTraceId())) {
                            builder.must(TermQuery.of(m -> m.field(E.buildKeyword(LogOperationElasticPo.Fields.traceId)).value(query.getTraceId()))._toQuery());
                        }
                        if (StringUtils.isNotBlank(query.getDeviceId())) {
                            builder.must(TermQuery.of(m -> m.field(E.buildKeyword("headerParams.device-id")).value(query.getDeviceId()))._toQuery());
                        }
                        if (query.getExcludeUserIds() != null && !query.getExcludeUserIds().isEmpty()) {
                            var values = query.getExcludeUserIds().stream().map(FieldValue::of).collect(Collectors.toList());
                            builder.mustNot(TermsQuery.of(m -> m.field(LogOperationElasticPo.Fields.fkUserId).terms(t -> t.value(values)))._toQuery());
                        }
                    })
                    .sortBuilder(query -> sort -> sort.field(field ->
                            field.field(LogOperationElasticPo.Fields.requestTime).order(SortOrder.Desc)
                    ))
                    .build();


}
